package cn.edu.hitwh.kanlema.util;

import cn.edu.hitwh.kanlema.constant.RedisConstants;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.connection.BitFieldSubCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Component
@RequiredArgsConstructor
public class SignUtil {
    private final RedisTemplate<String, String> redisTemplate;

    public void sign(Long userId, LocalDate day) {
        String key = RedisConstants.SIGN_KEY + day.format(RedisConstants.SIGN_KEY_MONTH_FORMATTER) + userId;
        redisTemplate.opsForValue()
                .setBit(key, day.getDayOfMonth() - 1, true);
        redisTemplate.expire(key, RedisConstants.SIGN_KEY_TTL, TimeUnit.HOURS);
    }

    public void sign(Long userId) {
        sign(userId, LocalDate.now());
    }

    public boolean isSigned(Long userId, LocalDate day) {
        String key = RedisConstants.SIGN_KEY + day.format(RedisConstants.SIGN_KEY_MONTH_FORMATTER) + userId;
        return Boolean.TRUE.equals(redisTemplate.opsForValue()
                .getBit(key, day.getDayOfMonth() - 1));
    }

    public long getSignCount(Long userId, LocalDate begin, LocalDate end) {
        if (begin.isAfter(end)) {
            return 0;
        }
        List<String> monthKeys = new ArrayList<>();
        for (LocalDate day = begin; !day.isAfter(end); day = day.plusDays(1)) {
            monthKeys.add(RedisConstants.SIGN_KEY + day.format(RedisConstants.SIGN_KEY_MONTH_FORMATTER) + userId);
        }
        // 第一个月的签到次数
        String firstKey = monthKeys.get(0);
        long firstDay = begin.getDayOfMonth() - 1;
        Long firstMonthSignCount = redisTemplate.execute(
                (RedisCallback<Long>) conn -> conn.bitCount(firstKey.getBytes(), firstDay, 31)
        );
        if (firstMonthSignCount == null) {
            firstMonthSignCount = 0L;
        }
        monthKeys.remove(0);
        if (monthKeys.isEmpty()) {
            return firstMonthSignCount;
        }
        // 最后一个月的签到次数
        String lastKey = monthKeys.get(monthKeys.size() - 1);
        long lastDay = end.getDayOfMonth() - 1;
        Long lastMonthSignCount = redisTemplate.execute(
                (RedisCallback<Long>) conn -> conn.bitCount(lastKey.getBytes(), 0, lastDay)
        );
        if (lastMonthSignCount == null) {
            lastMonthSignCount = 0L;
        }
        monthKeys.remove(monthKeys.size() - 1);
        if (monthKeys.isEmpty()) {
            return firstMonthSignCount + lastMonthSignCount;
        }
        long total = firstMonthSignCount + lastMonthSignCount;
        for (String key : monthKeys) {
            Long signCount = redisTemplate.execute(
                    (RedisCallback<Long>) conn -> conn.bitCount(key.getBytes(), 0, 31)
            );
            if (signCount == null) {
                signCount = 0L;
            }
            total += signCount;
        }
        return total;
    }
}
